home *** CD-ROM | disk | FTP | other *** search
- /* @(#)src/direct.c 1.5 7/11/92 11:48:20 */
-
- /*
- * Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
- * Copyright (C) 1992 Ronald S. Karr
- *
- * See the file COPYING, distributed with smail, for restriction
- * and warranty information.
- */
-
- /*
- * direct.c:
- * resolve local form addresses to more addresses or to transports
- *
- * external functions: direct_local_addrs, verify_local_addrs,
- * cache_directors, finish_directors,
- * director_user_info, find_director,
- * find_direct_driver, read_director_file.
- */
- #include <stdio.h>
- #include <pwd.h>
- #include <grp.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include "defs.h"
- #include "smail.h"
- #include "direct.h"
- #include "transport.h"
- #include "log.h"
- #include "addr.h"
- #include "main.h"
- #include "dys.h"
- #include "exitcodes.h"
- #include "smailconf.h"
- #ifndef DEPEND
- # include "debug.h"
- # include "extern.h"
- # include "error.h"
- #endif
-
- /* enums local to this file */
- enum local_form {
- FILE_FORM, /* filename address */
- PIPE_FORM, /* shell-command address */
- INCLUDE_FORM, /* mailing list address */
- OTHER_FORM, /* any other address form */
- };
- enum other_form_op {
- SEND_TO_NEXT, /* send addr to next director */
- DROP_ADDRESS, /* ignore addr */
- ADDRESS_OKAY, /* reparse address */
- };
-
- /* variables exported from this file */
- int cached_directors = FALSE; /* TRUE if cache_directors() called */
-
- /* functions local to this file */
- static void implicit_redirect();
- static enum other_form_op finish_direct_other_form();
- static void finish_direct_special_form();
- static void cache_director_data();
- static void premunge_local_addrs();
- static enum local_form addr_type();
- static int verify_special();
- static char *director_driv_function();
-
-
- /*
- * direct_local_addrs - produce finished and expanded addrs from local addrs
- *
- * this is called from resolve_addr_list to run local-form addresses
- * through the directors to completely resolve addr structures and
- * to transform them into a new list of addr structures to resolve.
- */
- void
- direct_local_addrs(in, out, retry, defer, fail)
- struct addr *in; /* input local-form addrs */
- struct addr **out; /* output resolved addrs */
- struct addr **retry; /* addr structures to reparse */
- struct addr **defer; /* addrs to defer to a later time */
- struct addr **fail; /* unresolvable addrs */
- {
- struct director *dp; /* temp for stepping thru directors */
- struct addr *cur; /* temp for stepping through addrs */
- struct addr *newaddrs; /* new addrs from a director */
- struct addr *includes; /* mailing list addrs */
- struct addr *next; /* next value for cur */
- DEBUG(DBG_DIRECT_HI, "direct_local_addrs called\n");
-
- /* do any munging of the addr structures required before directing */
- premunge_local_addrs(in);
-
- /*
- * call each director in turn, where each director
- * produces an output list a list of addrs it could
- * not resolve, and a list of addrs it resolved to
- * a list. The actual return value is the list it
- * could not resolve.
- */
- *retry = NULL;
- includes = NULL;
- while (in) {
- /*
- * directors are organized as subsections with the subsection
- * data being the director structures.
- */
- for (dp = directors; in && dp; dp = dp->succ) {
- /* look up the director driver by name */
- struct direct_driver *driver = find_direct_driver(dp->driver);
-
- if (driver == NULL) {
- /*
- * ERR_107 - director driver not found
- *
- * DESCRIPTION
- * A director driver was not found.
- *
- * ACTIONS
- * Defer all remaining input addresses with
- * configuration errors. Since it is not known if this
- * director would have matched any addresses, we cannot
- * pass the addresses on to the next director. Thus,
- * we must defer all addresses not matched by a
- * previous director.
- *
- * RESOLUTION
- * The postmaster must check the director and transport
- * configurations before delivery can be performed.
- */
- insert_addr_list(in,
- defer,
- note_error(ERR_CONFERR|ERR_107,
- xprintf(
- "director %s: driver %s driver not found",
- dp->name,
- dp->driver)));
- exitvalue = EX_DATAERR;
- return;
- }
- /* initialize list of new addrs found in this pass */
- newaddrs = NULL;
-
- /* call the driver */
- in = (*driver->driver)(dp, in, out, &newaddrs, defer, fail);
-
- /* step through newaddrs to verify them */
- for (cur = newaddrs; cur; cur = next) {
- enum local_form form = addr_type(cur->work_addr);
-
- next = cur->succ; /* note which addr to examine next */
-
- /*
- * read in cache data in the director structure, if this
- * has not yet been done.
- */
- if (! (dp->flags & CACHED_DIRECTOR) ) {
- cache_director_data(dp);
- }
-
- /* setup the uid, gid and home directories for the addr */
- if (dp->default_user) {
- if (cur->uid == BOGUS_USER) {
- cur->uid = dp->default_uid;
- }
- if (cur->gid == BOGUS_GROUP) {
- cur->gid = dp->default_gid;
- }
- }
- if (dp->default_home && cur->home == NULL) {
- cur->home = dp->x_default_home;
- }
- if (dp->set_user) {
- cur->uid = dp->set_uid;
- cur->gid = dp->set_gid;
- }
- if (dp->set_home) {
- cur->home = dp->x_set_home;
- }
-
- if (dp->flags & CAUTION_DIRECTOR) {
- /* be cautious on all addrs from this director */
- cur->flags |= ADDR_CAUTION;
- }
-
- if (form == OTHER_FORM) {
- switch (finish_direct_other_form(dp, cur)) {
- case SEND_TO_NEXT:
- /* matched the parent addr, send to next director */
- cur->succ = in;
- in = cur;
- break;
- case DROP_ADDRESS:
- /* matched the sender, drop the address */
- break;
- case ADDRESS_OKAY:
- /* address is okay, put back on the input */
- cur->succ = *retry;
- *retry = cur;
- break;
- }
- } else {
- finish_direct_special_form(cur, dp, form,
- retry, out, defer, fail,
- &includes);
- }
- }
- }
-
- /*
- * log addrs which were not directed anywhere
- */
- for (; in; in = next) {
- next = in->succ;
-
- #ifndef NO_PETER_HONEYMAN
- /*
- * Peter Honeyman once told us that he prefered flat address
- * spaces. You can help to further his cause by not defining
- * NO_PETER_HONEYMAN. If this is not defined then all mail
- * destined to the user `honey' or 'peter.honeyman' will be
- * sent to Peter Honeyman's mail address. When all machines
- * in the world use smail and don't define this, no user need
- * ever know Peter's address.
- */
- if (EQIC(in->remainder, "honey") ||
- EQIC(in->remainder, "peter.honeyman") ||
- EQIC(in->remainder, "peter honeyman"))
- {
- implicit_redirect(in, retry, "honey@citi.umich.edu");
- } else
- #endif /* NO_PETER_HONEYMAN */
- if (EQIC(in->remainder, "MAILER-DAEMON")) {
- implicit_redirect(in, retry, "Postmaster");
- } else if (EQIC(in->remainder, "Postmaster")) {
- implicit_redirect(in, retry, postmaster_address);
- } else {
- /* no director found the user, fail the address */
- exitvalue = EX_NOUSER; /* also set exit status */
- /*
- * ERR_100 - unknown user
- *
- * DESCRIPTION
- * The remainder structure in this addr structure was
- * not matched by any of the directors.
- *
- * ACTIONS
- * Send a message to the owner of the address, or to
- * the sender if there is no owner.
- *
- * RESOLUTION
- * A list owner should check through the list that he
- * or she owns. A sender may wish to send mail to the
- * postmaster of the machine asking about login names
- * for a particular user.
- */
- in->error = note_error(ERR_NSOWNER|ERR_100, "unknown user");
- in->succ = *fail;
- *fail = in;
- }
- }
-
- /*
- * copy any mailing list addrs back to the input
- * so they can be run back through the directors.
- */
- in = includes;
- includes = NULL;
- }
- }
-
-
- /*
- * verify_local_addrs - perform quick verify of local addresses
- *
- * form a list of okay (verified) addrs, plus deferred (not currently
- * determinable) addrs and failed (not deliverable) addrs.
- */
- void
- verify_local_addrs(in, okay, defer, fail)
- struct addr *in; /* input local addr list */
- struct addr **okay; /* output list of verified addrs */
- struct addr **defer; /* temporariliy unverifiable addrs */
- struct addr **fail; /* unverified addrs */
- {
- struct director *dp; /* temp for stepping thru directors */
- register struct addr *cur; /* temp for stepping through addrs */
- struct addr *next; /* next value for cur */
-
- DEBUG(DBG_ROUTE_HI, "verify_local_addrs called\n");
-
- /* do any munging of the addr structures required before directing */
- premunge_local_addrs(in);
-
- /*
- * give the complete input list to each director in turn.
- */
- for (dp = directors; in && dp; dp = dp->succ) {
- /* look up the director driver by name */
- struct direct_driver *driver = find_direct_driver(dp->driver);
- struct addr *retry; /* set of addrs for next director */
-
- if (driver == NULL) {
- /*
- * ERR_107 - director driver not found
- *
- * DESCRIPTION
- * A driver name was not found in the table of director
- * drivers.
- *
- * ACTIONS
- * Defer all remaining input addresses with configuration
- * errors. Since it is not known if this director would
- * have matched any addresses, we cannot pass the addresses
- * on to the next director. Thus, we must defer all
- * addresses not matched by a previous director.
- *
- * RESOLUTION
- * The postmaster must check the director and transport
- * configurations before delivery can be performed.
- */
- insert_addr_list(in,
- defer,
- note_error(ERR_CONFERR|ERR_107,
- xprintf(
- "director %s: driver %s driver not found",
- dp->name,
- dp->driver)));
- return;
- }
-
- /* call the driver */
- retry = NULL;
- (*driver->verify)(dp, in, &retry, okay, defer, fail);
- in = retry;
- }
-
- for (cur = in; cur; cur = next) {
- next = cur->succ;
-
- #ifndef NO_PETER_HONEYMAN
- /*
- * Peter Honeyman once told us that he prefered flat address
- * spaces. You can help to further his cause by not defining
- * NO_PETER_HONEYMAN. If this is not defined then all mail
- * destined to the user `honey' or 'peter.honeyman' will be
- * sent to Peter Honeyman's mail address. When all machines
- * in the world use smail and don't define this, no user need
- * ever know Peter's address.
- */
- if (EQIC(in->remainder, "honey") ||
- EQIC(in->remainder, "peter.honeyman") ||
- EQIC(in->remainder, "peter honeyman"))
- {
- cur->succ = *okay;
- *okay = cur;
- } else
- #endif /* NO_PETER_HONEYMAN */
- {
- /* no director found the user, fail the address */
- exitvalue = EX_NOUSER; /* also set exit status */
- /*
- * ERR_100 - unknown user
- *
- * DESCRIPTION
- * The remainder structure in this addr structure was not
- * matched by any of the directors.
- *
- * ACTIONS
- * Send a message to the owner of the address, or to the
- * sender if there is no owner.
- *
- * RESOLUTION
- * A list owner should check through the list that he or
- * she owns. A sender may wish to send mail to the
- * postmaster of the machine asking about login names for a
- * particular user.
- */
- cur->error = note_error(ERR_NSOWNER|ERR_100, "unknown user");
- cur->succ = *fail;
- *fail = cur;
- }
- }
- }
-
-
- /*
- * cache_directors - call cache entrypoints for all directors
- *
- * cache information used by director drivers. This can be called
- * when it is determined that there will be an attempt to deliver more
- * than one mail message, to increase the overall efficiency of the
- * mailer.
- *
- * Daemons can call this periodically to recache stale data.
- */
- void
- cache_directors()
- {
- struct director *dp; /* temp for stepping thru directors */
- struct direct_driver *driver;
-
- for (dp = directors; dp; dp = dp->succ) {
- driver = find_direct_driver(dp->driver);
- if (driver && driver->cache) {
- (*driver->cache)(dp);
- }
- }
- cached_directors = TRUE;
- }
-
- #ifdef notyet
- /*
- * finish_directors - free resources used by all directors
- *
- * free information that was cached by directors or used by directors
- * in the process of resolving local addresses. Directors can cache
- * data for efficiency, or can maintain state between invocations.
- * This function is called when directors will no longer be needed,
- * allowing directors to free any resources that they were using that
- * will no longer be needed. For example, it is a good idea for
- * directors to close any files that they opened, as file descriptors
- * are a precious resource in some machines.
- */
- void
- finish_directors()
- {
- struct directors *dp; /* temp for stepping thru directors */
- struct direct_driver *driver;
-
- for (dp = directors; dp; dp = dp->succ) {
- driver = find_direct_driver(dp->driver);
- if (driver && driver->finish) {
- (*driver->finish)(dp);
- }
- }
- cached_directors = FALSE;
- }
- #endif
-
-
- /*
- * implicit_redirect - an implicit director to redirect to the given address
- */
- static void
- implicit_redirect(match, retry, in_addr)
- struct addr *match; /* addr structure to direct */
- struct addr **retry; /* attach new addr to this list */
- char *in_addr; /* the text for the new address */
- {
- struct addr *new = alloc_addr();
- new->in_addr = COPY_STRING(in_addr);
- new->work_addr = COPY_STRING(in_addr);
- new->succ = *retry;
- *retry = new;
- DEBUG3(DBG_DIRECT_LO,
- "smail implicity matched %s\n directed %s --> %s\n",
- match->in_addr, match->in_addr, in_addr);
- }
-
- /*
- * finish_direct_other_form - finish directing a simple addr
- *
- * return SEND_TO_NEXT if this addr matches the parent addr and should
- * thus be sent to the next director rather than being put on the
- * list of new addrs.
- * return DROP_ADDRESS if this addr is in local form and matches the
- * sender and should thus be ignored. This value is not returned if
- * the `sender_okay' attribute is set for the director, or if the
- * me_too flag was set in the invocation arguments.
- * return ADDRESS_OKAY if the addr should be put on the list of
- * addresses to be reparsed.
- *
- * XXX - this may change the addr structure as a side effect, so watch out.
- */
- static enum other_form_op
- finish_direct_other_form(dp, addr)
- struct director *dp; /* director which returned addr */
- struct addr *addr; /* addr struct from director */
- {
- int parseflags;
-
- /* not an address form we need to be worried about */
- if (EQIC(addr->work_addr, addr->parent->remainder) ||
- (addr->work_addr[0] == '\\' &&
- EQIC(addr->work_addr + 1, addr->parent->remainder)))
- {
- /* for the form \parent-addr drop the \ */
- if (addr->work_addr[0] == '\\') {
- (void) strcpy(addr->work_addr, addr->work_addr + 1);
- }
-
- /*
- * new addr same as input addr, send to
- * the next director. E.g., foo aliased
- * to foo.
- */
- DEBUG2(DBG_DIRECT_LO,
- " directed %s --> %s ... matched, pass to next director\n",
- addr->parent->remainder,
- addr->work_addr);
- addr->remainder = addr->work_addr;
- return SEND_TO_NEXT;
- } else {
- /*
- * XXX - reparse the address looking for references
- * to the the localhost with a remainder equal
- * to the parent address. This allows the use
- * of username@localhost addresses in alias
- * files, making it possible to share an alias
- * file for redirecting users around a network.
- *
- * This moves intelligence out of resolve.c that
- * really belongs there.
- */
- char *temp_target;
- char *temp_remainder;
- char *temp_work_addr;
- int form;
-
- temp_work_addr = COPY_STRING(addr->work_addr);
- parseflags = addr->parseflags;
- form = parse_address(temp_work_addr, &temp_target, &temp_remainder,
- &parseflags);
-
- switch (form) {
- case FAIL:
- case PARSE_ERROR:
- xfree(temp_work_addr);
- break;
-
- case LOCAL:
- /*
- * if the me_too flag is not set, then filter the sender
- * from the output of directors. A director can
- * explicitly allow sender addresses to be produced by
- * including the `sender_okay' attribute. When expanding
- * an address list for verification purposes, the sender
- * may not be specified. Watch out for this case.
- */
- xfree(temp_work_addr);
- if (! (dp->flags & SENDER_OKAY) &&
- ! me_too &&
- sender &&
- EQIC(sender, addr->work_addr))
- {
- DEBUG2(DBG_DIRECT_LO,
- " directed %s --> %s ... match sender, ignore\n",
- addr->parent->remainder,
- addr->work_addr);
- return DROP_ADDRESS;
- }
- break;
-
- default:
- if (islocalhost(temp_target) &&
- EQIC(temp_remainder, addr->parent->remainder))
- {
- /*
- * new addr same as input addr, send to
- * the next director. E.g., foo aliased
- * to foo.
- */
- DEBUG2(DBG_DIRECT_LO,
- " directed %s --> %s ... match, pass to next director\n",
- addr->parent->remainder,
- addr->work_addr);
- (void) strcpy(addr->work_addr, temp_remainder);
- addr->remainder = addr->work_addr;
- xfree(temp_work_addr);
- return SEND_TO_NEXT;
- }
- }
- }
-
- /* we have a new address to reparse */
- DEBUG2(DBG_DIRECT_LO, " directed %s --> %s\n",
- addr->parent->remainder,
- addr->in_addr);
-
- return ADDRESS_OKAY;
- }
-
- /*
- * finish_direct_special_form - direct a file, pipe or mailing list form addr
- */
- /*ARGSUSED*/
- static void
- finish_direct_special_form(addr, dp, form, new, out, defer, fail, includes)
- struct addr *addr; /* addr structure to finish */
- struct director *dp; /* matching director */
- enum local_form form; /* local address form */
- struct addr **new; /* put new addrs to retry here */
- struct addr **out; /* resolved addrs */
- struct addr **defer; /* put config errors here */
- struct addr **fail; /* put failed addrs here */
- struct addr **includes; /* include file forms */
- {
- /* save a pointer to the pipe transport */
- static struct transport *pipe_transport = NULL;
- /* save a pointer to the file transport */
- static struct transport *file_transport = NULL;
-
- /*
- * not a regular address, should we keep it or drop it?
- *
- * NOTE: unsecure addresses are less secure than addresses which
- * are not secure. Addresses which are not secure may have
- * accesses checked under the nobody uid/gid. Unsecure
- * pipes, files and mailing lists are are always dropped.
- */
- /* only hash normal-form addresses */
- addr->flags |= ADDR_DONTHASH;
- if ((addr->flags & ADDR_UNSECURE) ||
- ((addr->flags & ADDR_CAUTION) && ! (dp->flags & NOBODY_DIRECTOR)))
- {
- /*
- * ERR_104 - security violation
- *
- * DESCRIPTION
- * A questionable address was supplied from a director
- * that is not allowed to supply a file command or
- * mailing list.
- *
- * ACTIONS
- * mail is sent to the address owner or to the
- * postmaster.
- *
- * RESOLUTION
- * The owner or postmaster should check the source source
- * of addresses against any file ownership restrictions
- * named in the director.
- */
- addr->error = note_error(ERR_NPOWNER|ERR_104,
- xprintf("director %s: security violation",
- dp->name));
- addr->succ = *fail;
- *fail = addr;
- return;
- }
- if (addr->flags & ADDR_CAUTION) {
- /* be cautious of addresses, but nobody is set */
- if (operation_mode != VERIFY_ADDRS &&
- operation_mode != TEST_MODE)
- {
- write_log(LOG_SYS,
- "%s ... director %s: child of %s insecure, access as 'nobody'",
- addr->in_addr,
- dp->name,
- addr->parent->in_addr);
- }
- addr->uid = nobody_uid;
- addr->gid = nobody_gid;
- }
-
- /* passed security checks, now what do we do? */
- switch (form) {
-
- case PIPE_FORM:
- /*
- * pipe form, associate with the "pipe" transport
- */
- if (pipe_transport == NULL) {
- pipe_transport = find_transport("pipe");
- if (pipe_transport == NULL) {
- /* configuration error, try again later */
- /*
- * ERR_105 - no pipe transport
- *
- * DESCRIPTION
- * There is no "pipe" transport in the
- * table of transports, and a shell command
- * address returned by a director.
- *
- * ACTIONS
- * Defer message as a configuration error.
- *
- * RESOLUTION
- * The postmaster should add a "pipe"
- * transport to the transport file.
- */
- addr->error = note_error(ERR_CONFERR|ERR_105,
- "no pipe transport");
- addr->succ = *defer;
- *defer = addr;
- break;
- }
- }
-
- addr->transport = pipe_transport;
- /* setup command as $user variable for transports */
- addr->next_addr = COPY_STRING(addr->work_addr + 1);
- DEBUG2(DBG_DIRECT_LO,
- " directed %s --> %s ... send to pipe transport\n",
- addr->parent->remainder,
- addr->in_addr);
- /* addr finished link into the output queue */
- addr->succ = *out;
- *out = addr;
- break;
-
- case FILE_FORM:
- /*
- * file form, associate with the "file" transport
- */
- if (file_transport == NULL) {
- file_transport = find_transport("file");
- if (file_transport == NULL) {
- /* configuration error, must be fixed */
- /*
- * ERR_106 - no file transport
- *
- * DESCRIPTION
- * There is no "file" transport in the
- * table of transports, and a file form
- * address was returned by a director.
- *
- * ACTIONS
- * Defer message as a configuration error.
- *
- * RESOLUTION
- * The postmaster should add a "file"
- * transport to the transport file.
- */
- addr->error = note_error(ERR_CONFERR|ERR_106,
- "no file transport");
- addr->succ = *defer;
- *defer = addr;
- break;
- }
- }
- addr->transport = file_transport;
-
- /* setup file as $user variable for transports */
- addr->next_addr = COPY_STRING(addr->work_addr);
- DEBUG2(DBG_DIRECT_LO,
- " directed %s --> %s ... send to file transport\n",
- addr->parent->remainder,
- addr->in_addr);
- /* addr finished link into the output queue */
- addr->succ = *out;
- *out = addr;
- break;
-
- case INCLUDE_FORM:
- /* mailing lists go back through all the directors */
- DEBUG2(DBG_DIRECT_LO,
- " directed %s --> %s ... mailing list\n",
- addr->parent->remainder,
- addr->in_addr);
- /* set local part to the mailing list address */
- addr->remainder = addr->work_addr;
- addr->succ = *includes;
- *includes = addr;
- break;
- }
- }
-
-
- /*
- * cache_director_data - cache in some generic director information
- *
- * perform once on each director to perform some lookup and expansion
- * operations that would otherwise have to be performed each time these
- * values are used.
- */
- static void
- cache_director_data(dp)
- register struct director *dp;
- {
- if (dp->default_user) {
- struct passwd *pw = getpwbyname(dp->default_user);
- if (pw) {
- dp->default_uid = pw->pw_uid;
- dp->default_gid = pw->pw_gid;
- } else {
- dp->default_user = NULL;
- }
- }
- if (dp->default_group) {
- struct group *gr = getgrbyname(dp->default_group);
- if (gr) {
- dp->default_gid = gr->gr_gid;
- } else {
- dp->default_group = NULL;
- }
- }
- if (dp->default_home) {
- char *x_home =
- expand_string(dp->default_home,
- (struct addr *)NULL,
- (char *)NULL,
- (char *)NULL);
- if (x_home && !EQ(x_home, dp->default_home)) {
- dp->x_default_home = COPY_STRING(x_home);
- } else {
- dp->x_default_home = dp->default_home;
- }
- }
- if (dp->set_user) {
- struct passwd *pw = getpwbyname(dp->set_user);
- if (pw) {
- dp->set_uid = pw->pw_uid;
- dp->set_gid = pw->pw_gid;
- } else {
- dp->set_user = NULL;
- }
- }
- if (dp->set_group) {
- struct group *gr = getgrbyname(dp->set_group);
- if (gr) {
- dp->set_gid = gr->gr_gid;
- } else {
- dp->set_group = NULL;
- }
- }
- if (dp->set_home) {
- char *x_home =
- expand_string(dp->set_home,
- (struct addr *)NULL,
- (char *)NULL,
- (char *)NULL);
- if (x_home && !EQ(x_home, dp->set_home)) {
- dp->x_set_home = COPY_STRING(x_home);
- } else {
- dp->x_set_home = dp->set_home;
- }
- }
- }
-
- /*
- * premunge_local_addrs - pre-routing munging on local addr structures
- *
- * Remove any extraneously set flags.
- */
- static void
- premunge_local_addrs(list)
- struct addr *list; /* list of remote addrs to premunge */
- {
- register struct addr *cur; /* current address being processed */
-
- for (cur = list; cur; cur = cur->succ) {
- cur->flags &= ~(ADDR_PUTDOT |
- ADDR_MOVEDOT |
- ADDR_ERROR |
- ADDR_FINISHED |
- ADDR_FULLMATCH |
- ADDR_NOTUSER |
- ADDR_ISUSER);
- }
- }
-
- /*
- * addr_type - return the form of a local address string
- *
- * Determine if the address is a pipe, file, mailing list,
- * or other.
- */
- static enum local_form
- addr_type(s)
- register char *s;
- {
- /*
- * file is one of:
- * "/string"
- * "\/string"
- * "~string"
- * "\~string"
- * /string
- * \/string
- * ~string
- * \~string
- */
- if (s[0] == '"' && ((s[1] == '/' || s[1] == '~') ||
- (s[1] == '\\' && (s[2] == '/' || s[2] == '~'))))
- {
- /* file form, but only if the address is in local form */
- register char *p = address_token(s);
-
- if (p && *p == '\0') {
- /* address is in local form, strip work_addr inline */
- (void) strip(s);
- return FILE_FORM;
- }
- }
- if (s[0] == '/' || s[0] == '~' ||
- (s[0] == '\\' && (s[1] == '/' || s[1] == '~')))
- {
- /* filename not quoted, don't check for local form in this case */
- (void) strip(s);
- return FILE_FORM;
- }
-
- /*
- * pipe is one of:
- * "|shell-command"
- * "\|shell-command"
- * |shell-command
- * \|shell-command
- */
- if (s[0] == '"' && (s[1] == '|' || (s[1] == '\\' && s[2] == '|'))) {
- /* pipe form, but only if the address is in local form */
- char *p = address_token(s);
-
- if (p && *p == '\0') {
- /* address is in local form, strip work_addr inline */
- (void) strip(s);
- return PIPE_FORM;
- }
- }
- if (s[0] == '|' || (s[0] == '\\' && s[1] == '|')) {
- /* shell command not quoted, don't check for local form in this case */
- (void) strip(s);
- return PIPE_FORM;
- }
-
- /*
- * mailing list is one of:
- * :include:anything
- * ":include:anything"
- */
- if (s[0] == '"' && s[1] == ':' &&
- strncmpic(s + 2, "include:", sizeof("include:") - 1) == 0)
- {
- /* mailing list form, but only if the address is in local form */
- char *p = address_token(s);
-
- if (p && *p == '\0') {
- /* address is in local form, strip work_addr inline */
- (void) strip(s);
- return INCLUDE_FORM;
- }
- }
-
- if (s[0] == ':' && strncmpic(s+1, "include:", sizeof("include:")-1) == 0)
- {
- /* shell command not quoted, don't check for local form in this case */
- return INCLUDE_FORM;
- }
-
- return OTHER_FORM;
- }
-
- /*
- * director_user_info - fill an addr structure with user information
- *
- *
- * if the remainder field if the addr structure matches a username,
- * fill in fields which pertain to the user's passwd file entry.
- */
- void
- director_user_info(addr)
- struct addr *addr; /* addr structure to check */
- {
- struct passwd *pw; /* passwd file entry for user */
-
- if (addr->flags & (ADDR_NOTUSER|ADDR_ISUSER)) {
- /* a previous call to director_user_info() already took care of this */
- return;
- }
-
- /* get the passwd entry if one exists */
- pw = getpwbyname(addr->remainder);
- if (pw) {
- /* passwd entry found */
- addr->flags |= ADDR_ISUSER;
- addr->uid = pw->pw_uid;
- addr->gid = pw->pw_gid;
- addr->home = COPY_STRING(pw->pw_dir);
- return;
- }
-
- /* no passwd entry found */
- addr->flags |= ADDR_NOTUSER;
- return;
- }
-
-
- /*
- * find_director - given a director's name, return the director structure
- *
- * return NULL if no director of that name exists.
- */
- struct director *
- find_director(name)
- register char *name; /* search key */
- {
- register struct director *dp; /* temp for stepping thru directors */
-
- /* loop through all the directors */
- for (dp = directors; dp; dp = dp->succ) {
- if (EQ(dp->name, name)) {
- /* found the director in question */
- return dp;
- }
- }
-
- return NULL; /* director not found */
- }
-
- /*
- * find_direct_driver - given a driver's name, return the driver structure
- *
- * return NULL if driver does not exist.
- */
- struct direct_driver *
- find_direct_driver(name)
- register char *name; /* search key */
- {
- register struct direct_driver *ddp; /* pointer to table of drivers */
-
- for (ddp = direct_drivers; ddp->name; ddp++) {
- if (EQ(ddp->name, name)) {
- return ddp; /* found the driver */
- }
- }
-
- return NULL; /* driver not found */
- }
-
-
- /*
- * read_director_file - read director file
- *
- * read the director file and build a director list describing the
- * entries. Return an error message or NULL.
- */
- char *
- read_director_file()
- {
- FILE *f; /* open director file */
- char *error; /* error from read_standard_file() */
- struct stat statbuf;
- static struct attr_table director_generic[] = {
- { "driver", t_string, NULL, NULL, OFFSET(director, driver) },
- { "caution", t_boolean, NULL, NULL, CAUTION_DIRECTOR },
- { "nobody", t_boolean, NULL, NULL, NOBODY_DIRECTOR },
- { "sender_okay", t_boolean, NULL, NULL, SENDER_OKAY },
- { "owner", t_string, NULL, NULL, OFFSET(director, owner) },
- { "default_user", t_string, NULL, NULL,
- OFFSET(director, default_user) },
- { "default_group", t_string, NULL, NULL,
- OFFSET(director, default_group) },
- { "default_home", t_string, NULL, NULL,
- OFFSET(director, default_home) },
- { "set_user", t_string, NULL, NULL, OFFSET(director, set_user) },
- { "set_group", t_string, NULL, NULL, OFFSET(director, set_group) },
- { "set_home", t_string, NULL, NULL, OFFSET(director, set_home) },
- };
- struct attr_table *end_director_generic = ENDTABLE(director_generic);
- static struct director director_template = {
- NULL, /* name */
- "pathalias", /* driver, a reasonable default */
- NULL, /* succ will be assigned */
- NOBODY_DIRECTOR, /* flags */
- NULL, /* owner */
- NULL, /* default_user */
- NULL, /* default_group */
- NULL, /* default_home */
- NULL, /* set_user */
- NULL, /* set_group */
- NULL, /* set_home */
- NULL, /* private */
- 0, /* cache - default_uid */
- 0, /* cache - default_gid */
- NULL, /* cache - x_default_home */
- 0, /* cache - set_uid */
- 0, /* cache - set_gid */
- NULL, /* cache - x_set_home */
- };
-
- /*
- * try to open directory file, stat file if possible
- */
- if (director_file == NULL || EQ(director_file, "-")) {
- return NULL;
- }
- f = fopen(director_file, "r");
- if (f == NULL) {
- if (require_configs) {
- return xprintf("%s:%s", director_file, strerrno());
- }
-
- add_config_stat(director_file, (struct stat *)NULL);
- return NULL;
- }
-
- (void)fstat(fileno(f), &statbuf);
- add_config_stat(director_file, &statbuf);
-
- /* call read_standard_file to do the real work */
- error = read_standard_file(f,
- (char *)&director_template,
- sizeof(struct director),
- OFFSET(director, name),
- OFFSET(director, flags),
- OFFSET(director, succ),
- director_generic,
- end_director_generic,
- director_driv_function,
- (char **)&directors);
-
- /* finish up */
- (void) fclose(f);
-
- /* return any error message */
- if (error) {
- return xprintf("%s: %s", director_file, error);
- }
- return NULL;
- }
-
- static char *
- director_driv_function(struct_p, driver_attrs)
- char *struct_p; /* passed director structure */
- struct attribute *driver_attrs; /* driver-specific attributes */
- {
- struct director *dp = (struct director *)struct_p;
- struct direct_driver *drv;
-
- if (dp->driver == NULL) {
- return xprintf("director %s: no driver attribute", dp->name);
- }
- drv = find_direct_driver(dp->driver);
- if (drv == NULL) {
- return xprintf("director %s: unknown driver: %s",
- dp->name, dp->driver);
- }
- if (drv->builder) {
- return (*drv->builder)(dp, driver_attrs);
- }
-
- return NULL;
- }
-